package com.jeesite.modules.flow.web;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.activiti.bpmn.converter.BpmnXMLConverter;
import org.activiti.bpmn.model.BpmnModel;
import org.activiti.editor.constants.ModelDataJsonConstants;
import org.activiti.editor.language.json.converter.BpmnJsonConverter;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.repository.Deployment;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.util.CollectionUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import com.jeesite.common.config.Global;
import com.jeesite.common.entity.Page;
import com.jeesite.common.web.BaseController;
import com.jeesite.modules.flow.entity.ActReModel;
import com.jeesite.modules.flow.service.ActReModelService;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

import java.io.ByteArrayInputStream;
import java.io.IOException;

import static org.activiti.editor.constants.ModelDataJsonConstants.MODEL_DESCRIPTION;
import static org.activiti.editor.constants.ModelDataJsonConstants.MODEL_NAME;

/**
 * 流程模型信息Controller
 * @author lihp
 * @version 2024-08-29
 */
@Controller
@RequestMapping(value = "${adminPath}/flow/model")
public class ActReModelController extends BaseController {

	@Autowired
	private ActReModelService actReModelService;
	@Autowired
	private RepositoryService repositoryService;
	
	/**
	 * 获取数据
	 */
	@ModelAttribute
	public ActReModel get(String id, boolean isNewRecord) {
		return actReModelService.get(id, isNewRecord);
	}
	
	/**
	 * 查询列表
	 */
	@RequestMapping(value = {"list", ""})
	public String list(ActReModel actReModel, Model model) {
		model.addAttribute("actReModel", actReModel);
		return "modules/flow/model/modelList";
	}
	
	/**
	 * 查询列表数据
	 */
	@RequestMapping(value = "listData")
	@ResponseBody
	public Page<ActReModel> listData(ActReModel actReModel, HttpServletRequest request, HttpServletResponse response) {
		actReModel.setPage(new Page<>(request, response));
		Page<ActReModel> page = actReModelService.findPage(actReModel);
		return page;
	}

	/**
	 * 查看编辑表单
	 */
	@RequestMapping(value = "form")
	public String form(ActReModel actReModel, Model model) {
		model.addAttribute("actReModel", actReModel);
		return "modules/flow/model/modelForm";
	}

	/**
	 * 保存数据
	 */
	@PostMapping(value = "save")
	@ResponseBody
	public String save(@Validated ActReModel actReModel) {
		try {
			ObjectMapper objectMapper = new ObjectMapper();
			ObjectNode editorNode = objectMapper.createObjectNode();
			editorNode.put("id", "canvas");
			editorNode.put("resourceId", "canvas");
			ObjectNode stencilSetNode = objectMapper.createObjectNode();
			stencilSetNode.put("namespace", "http://b3mn.org/stencilset/bpmn2.0#");
			editorNode.put("stencilset", stencilSetNode);

			ObjectNode modelObjectNode = objectMapper.createObjectNode();
			modelObjectNode.put(MODEL_NAME, actReModel.getName());
			modelObjectNode.put(ModelDataJsonConstants.MODEL_REVISION, 1);
			String description = StringUtils.defaultString(actReModel.getMetaInfo());
			modelObjectNode.put(MODEL_DESCRIPTION, description);

			org.activiti.engine.repository.Model newModel = repositoryService.newModel();
			newModel.setMetaInfo(modelObjectNode.toString());
			newModel.setName(actReModel.getName());
			newModel.setKey(StringUtils.defaultString(actReModel.getKey()));

			repositoryService.saveModel(newModel);
			repositoryService.addModelEditorSource(newModel.getId(), editorNode.toString().getBytes("utf-8"));

			return renderResult(Global.TRUE, text("创建模型成功！"), newModel.getId());
		} catch (Exception e) {
			logger.error("创建模型失败：", e);
		}
		return renderResult(Global.FALSE, text("创建模型失败！"));
	}

	/**
	 * 根据Model部署流程
	 */
	@RequestMapping(value = "deployFlow")
	@ResponseBody
	public String deployFlow(ActReModel actReModel) {
		try {
			org.activiti.engine.repository.Model modelData = repositoryService.getModel(actReModel.getId());
			ObjectNode modelNode = (ObjectNode) new ObjectMapper().readTree(repositoryService.getModelEditorSource(modelData.getId()));
			byte[] bpmnBytes = null;

			BpmnModel model = new BpmnJsonConverter().convertToBpmnModel(modelNode);
			bpmnBytes = new BpmnXMLConverter().convertToXML(model);

			String processName = modelData.getName() + ".bpmn20.xml";
			Deployment deployment = repositoryService.createDeployment().name(modelData.getName()).addString(processName, new String(bpmnBytes, "UTF-8")).deploy();

			logger.info("部署成功，部署ID=" + deployment.getId());
			return renderResult(Global.TRUE, text("模型部署成功！"));
		} catch (Exception e) {
			logger.error("根据模型部署流程失败：modelId={}", actReModel.getId(), e);
			return renderResult(Global.FALSE, text("模型部署失败！"));
		}
	}

	/**
	 * 导出model的xml文件
	 */
	@RequestMapping(value = "exportData")
	public void exportData(ActReModel actReModel, HttpServletResponse response) {
		try {
			org.activiti.engine.repository.Model modelData = repositoryService.getModel(actReModel.getId());
			BpmnJsonConverter jsonConverter = new BpmnJsonConverter();
			JsonNode editorNode = new ObjectMapper().readTree(repositoryService.getModelEditorSource(modelData.getId()));
			BpmnModel bpmnModel = jsonConverter.convertToBpmnModel(editorNode);

			// 流程非空判断
			if (!CollectionUtils.isEmpty(bpmnModel.getProcesses())) {
				BpmnXMLConverter xmlConverter = new BpmnXMLConverter();
				byte[] bpmnBytes = xmlConverter.convertToXML(bpmnModel);

				ByteArrayInputStream in = new ByteArrayInputStream(bpmnBytes);
				String filename = bpmnModel.getMainProcess().getId() + ".bpmn";
				response.setHeader("Content-Disposition", "attachment; filename=" + filename);
				IOUtils.copy(in, response.getOutputStream());
				response.flushBuffer();
			}
		} catch (Exception e) {
			logger.error("导出model的xml文件失败：modelId={}", actReModel.getId(), e);
			e.printStackTrace();
		}
	}
	
	/**
	 * 删除数据
	 */
	@RequestMapping(value = "delete")
	@ResponseBody
	public String delete(ActReModel actReModel) {
		try {
			repositoryService.deleteModel(actReModel.getId());
			return renderResult(Global.TRUE, text("模型删除成功！"));
		}
		catch (Exception e) {
			return renderResult(Global.FALSE, text(e.getMessage()));
		}
	}
	
}